package com.suray.wcs.service.thread;


import com.suray.basic.wcs.path.properties.PathProperties;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.wcs.res.enums.RgvStatus;
import com.suray.wcs.service.core.path.api.RgvTaskAssign;
import com.suray.wcs.service.core.util.CommonUtil;
import com.suray.wcs.service.core.util.SysConfigUtil;
import com.suray.wcs.service.enums.*;
import com.suray.wcs.service.init.SystemInit;
import com.suray.wcs.service.pojo.Rgv;
import com.suray.wcs.service.system.entity.NodeDB;
import com.suray.wcs.service.system.entity.TaskDB;
import com.suray.wcs.service.system.service.INodeDBService;
import com.suray.wcs.service.system.service.ITaskDBService;
import com.suray.wcs.service.system.service.IWareHouseDBService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.List;

/**
 * @author Shaozn
 */
public class AssignTaskThread extends Thread {
    private static Logger log = LoggerFactory.getLogger(AssignTaskThread.class);
    private final ITaskDBService taskDBService = SpringContextHolder.getBean(ITaskDBService.class);
    private RgvTaskAssign rgvTaskAssign = SpringContextHolder.getBean(RgvTaskAssign.class);
    private final INodeDBService nodeDBService = SpringContextHolder.getBean(INodeDBService.class);
    private final IWareHouseDBService iWareHouseDBService = SpringContextHolder.getBean(IWareHouseDBService.class);
    private Rgv rgv;
    /**
     * 分配任务间隔时间
     */
    private static final int INTERVAL_TIME = 1000;
    // 不可执行任务状态计时
    private Integer timeOutCount = 0;

    /**
     * 构造方法
     */
    public AssignTaskThread(Rgv rgv) {
        super(rgv.getRgvDB().getRgvNo() + "号车分配任务线程");
        this.rgv = rgv;
    }

    @Override
    public void run() {
        while (true) {
            try {
                // 1.判断小车是否低电量或小车故障、离线、未定位、禁用超时，如果是，
                // 如果当前任务数量为大于0，则把这些任务找出来，如果任务的状态为等待执行中，重新分配（如果有两个任务，其中一个是执行中，另一个是等待执行中，则把等待执行中的任务和预分配任务重新放到
                // 预分配队列中）
                if (canReassign(rgv)) {
                    List<TaskDB> canReAssignTaskList = taskDBService.findCanReAssignTaskList(rgv.getRgvDB().getRgvNo());
                    if (CollectionUtils.isNotEmpty(canReAssignTaskList)) {
                        for (TaskDB taskDB : canReAssignTaskList) {
                            if (taskDB.getTaskStatus() == TaskStatus.WAIT || taskDB.getTaskStatus() == TaskStatus.AVOID) {
                                //已分配的任务，重新调整预分配
                                taskDBService.updateTaskProcessingRgvNoAndPreProcessingRgvNo(taskDB, null, TaskRgvProgress.PREASSIGN, false);
                            } else {
                                log.info("{}已在不可执行任务状态超时，但是仍然存在进行中的任务{},请人工处理小车状态和任务", rgv, taskDB);
                            }
                        }
                    }
                }

                List<TaskDB> taskList = taskDBService.findCanExecuteTaskList(rgv.getRgvDB().getRgvNo());
                int taskCount = CollectionUtils.isNotEmpty(taskList) ? taskList.size() : 0;
                List<TaskDB> preTaskList = taskDBService.findPreTaskList(rgv.getRgvDB().getRgvNo());
                while (taskCount < SysConfigUtil.TASK_COUNT && CollectionUtils.isNotEmpty(preTaskList)) {
                    // 更新该任务的执行车辆为当前车辆
                    if (canAssign(rgv)) {
                        break;
                    }
                    if (TaskType.TRANSFER.equals(preTaskList.get(0).getTaskType())) {
                        log.info("任务分配线程,移库任务-->" + "插入时间和优先级模式（默认）");
                        taskDBService.updateTaskProcessingRgvAndTaskRgvProgress(rgv, preTaskList.get(0), TaskStatus.WAIT, TaskRgvProgress.ASSIGNED_TO_RGV);
                    } else {
                        // 入库优先，出库优先，出入库均衡，优先级加插入时间
                        if (PriorityMode.IN.getValue().equals(rgv.getRgvDB().getPriorityMode())) {
                            assignPriorityTask(rgv.getRgvDB().getRgvNo(), preTaskList, TaskType.IN);
                        } else if (PriorityMode.OUT.getValue().equals(rgv.getRgvDB().getPriorityMode())) {
                            assignPriorityTask(rgv.getRgvDB().getRgvNo(), preTaskList, TaskType.OUT);
                        } else if (PriorityMode.BALANCE.getValue().equals(rgv.getRgvDB().getPriorityMode())) {
                            if (CollectionUtils.isNotEmpty(taskList)) {
                                TaskDB lastTaskDB = taskList.get(taskList.size() - 1);
                                if (TaskType.IN.equals(lastTaskDB.getTaskType())) {
                                    assignPriorityTask(rgv.getRgvDB().getRgvNo(), preTaskList, TaskType.OUT);
                                } else if (TaskType.OUT.equals(lastTaskDB.getTaskType())) {
                                    assignPriorityTask(rgv.getRgvDB().getRgvNo(), preTaskList, TaskType.IN);
                                } else {
                                    taskDBService.updateTaskProcessingRgvAndTaskRgvProgress(rgv, preTaskList.get(0), TaskStatus.WAIT, TaskRgvProgress.ASSIGNED_TO_RGV);
                                }
                            } else {
                                taskDBService.updateTaskProcessingRgvAndTaskRgvProgress(rgv, preTaskList.get(0), TaskStatus.WAIT, TaskRgvProgress.ASSIGNED_TO_RGV);
                            }
                        } else if (PriorityMode.PRIORITY_INSERT_TIME.getValue().equals(iWareHouseDBService.getPriorityMode())) {
                            taskDBService.updateTaskProcessingRgvAndTaskRgvProgress(rgv, preTaskList.get(0), TaskStatus.WAIT, TaskRgvProgress.ASSIGNED_TO_RGV);
                        } else {
                            taskDBService.updateTaskProcessingRgvAndTaskRgvProgress(rgv, preTaskList.get(0), TaskStatus.WAIT, TaskRgvProgress.ASSIGNED_TO_RGV);
                        }
                    }
                    taskList = taskDBService.findCanExecuteTaskList(rgv.getRgvDB().getRgvNo());
                    taskCount = CollectionUtils.isNotEmpty(taskList) ? taskList.size() : 0;
                    preTaskList = taskDBService.findPreTaskList(rgv.getRgvDB().getRgvNo());
                    Thread.sleep(1000);
                }
                // 已达到分配个数但是还存在预分配该车的任务
                if (CollectionUtils.isNotEmpty(preTaskList)) {
                    if (checkReAssignRgv(rgv, preTaskList)) {
                        reAssignPreTask(preTaskList);
                    }
                }
                if (PriorityMode.IN.getValue().equals(rgv.getRgvDB().getPriorityMode())
                        || PriorityMode.OUT.getValue().equals(rgv.getRgvDB().getPriorityMode())) {
                    List<TaskDB> priorityTaskList = taskDBService.findPreTaskListByTaskType(rgv.getRgvDB().getRgvNo(),
                            PriorityMode.IN.getValue().equals(rgv.getRgvDB().getPriorityMode()) ? TaskType.OUT : TaskType.IN);
                    if (CollectionUtils.isNotEmpty(priorityTaskList)) {
                        reAssignPreTask(preTaskList);
                    }
                }

                if (rgv.getRgvStatus() == null
                        || rgv.getRgvStatus() == RgvStatus.ERROR || rgv.getCurLocation() == null || !rgv.getRgvDB().getOnline()) {
                    if (timeOutCount > 60000) {
                        timeOutCount = SysConfigUtil.NO_ASSIGN_TASK_TIME_OUT;
                    }
                    timeOutCount++;
                } else {
                    timeOutCount = 0;
                }
                try {
                    Thread.sleep(INTERVAL_TIME);
                } catch (InterruptedException e) {
                    log.error(this.getName() + "message:{}", e);
                }
            } catch (Exception e) {
                try {
                    Thread.sleep(INTERVAL_TIME);
                } catch (InterruptedException ex) {
                    log.error(this.getName() + "message:{}", ex);
                }
                log.error(this.getName() + "message:{}", e);
            }
        }
    }

    private void reAssignPreTask(List<TaskDB> preTaskList) {
        Iterator<TaskDB> it = preTaskList.iterator();
        while (it.hasNext()) {
            TaskDB preTaskDB = it.next();
            it.remove();
            Rgv bestRgv = rgvTaskAssign.bindAvailableRgvWithTask(preTaskDB);
            if (bestRgv == null) {
                List<TaskDB> list = taskDBService.findTasksByGroupId(preTaskDB.getTaskId(), preTaskDB.getGroupId(), CommonUtil.PRE_PROCESSING_RGV_NO_NOT_NULL_PROCESSING_RGV_NO_NULL);
                if (CollectionUtils.isNotEmpty(list)) {
                    preTaskList.removeAll(list);
                    it = preTaskList.iterator();
                }
            } else {
                if (!rgv.getRgvDB().getRgvNo().equals(bestRgv.getRgvDB().getRgvNo())) {
                    // 必须分给一个车的任务
                    List<TaskDB> currentRgvList = taskDBService.findTasksBySingleRgvFlagAndRgvNo(preTaskDB, bestRgv.getRgvDB().getRgvNo());
                    if (CollectionUtils.isEmpty(currentRgvList)) {
                        currentRgvList = taskDBService.findTasksBySingleRgvFlag(preTaskDB.getSingleRgvFlag(), CommonUtil.PRE_PROCESSING_RGV_NO_NOT_NULL_PROCESSING_RGV_NO_NULL);
                        if (CollectionUtils.isNotEmpty(currentRgvList)) {
                            preTaskList.removeAll(currentRgvList);
                            it = preTaskList.iterator();
                            for (TaskDB task : currentRgvList) {
                                taskDBService.updateTaskPreProcessingRgv(bestRgv, task);
                            }
                        } else {
                            taskDBService.updateTaskPreProcessingRgv(bestRgv, preTaskDB);
                        }
                    }
                } else {
                    List<TaskDB> noCurrentRgvList = taskDBService.findTasksBySingleRgvFlag(preTaskDB.getSingleRgvFlag(), CommonUtil.PRE_PROCESSING_RGV_NO_NOT_NULL_PROCESSING_RGV_NO_NULL);
                    if (CollectionUtils.isNotEmpty(noCurrentRgvList)) {
                        preTaskList.removeAll(noCurrentRgvList);
                        it = preTaskList.iterator();
                    }
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 正式分车，如果有优先模式配置则按优先模式正式分车，反之，按默认优先方式正式分车
     */
    private void assignPriorityTask(Integer rgvNo, List<TaskDB> preTaskList, TaskType taskType) {
        List<TaskDB> priorityTaskList = taskDBService.findPreTaskListByTaskType(rgvNo, taskType);
        if (CollectionUtils.isNotEmpty(priorityTaskList)) {
            taskDBService.updateTaskProcessingRgvAndTaskRgvProgress(rgv, priorityTaskList.get(0), TaskStatus.WAIT, TaskRgvProgress.ASSIGNED_TO_RGV);
        } else {
            taskDBService.updateTaskProcessingRgvAndTaskRgvProgress(rgv, preTaskList.get(0), TaskStatus.WAIT, TaskRgvProgress.ASSIGNED_TO_RGV);
        }
    }

    /**
     * 校验是否需要重新预分配的条件
     */
    private boolean checkReAssignRgv(Rgv rgv, List<TaskDB> preTaskList) {
        if (canReassign(rgv)) {
            return true;
        }
        if (hasReadRgvForCurrentFloor(rgv)) {
            return true;
        }
        if (existUnFinishChargingTask(rgv)) {
            return true;
        }
        if (existNoCurrentFloorTask(rgv, preTaskList)) {
            return true;
        }
        return false;
    }

    /**
     * 当前层当前区域是否有空闲的车，如果有，则重新预分配
     */
    private boolean hasReadRgvForCurrentFloor(Rgv rgv) {
        if (rgv.getCurLocation() != null) {
            NodeDB nodeDB = nodeDBService.getNodeDB(rgv.getCurLocation());
            if (nodeDB != null) {
                List<Rgv> currentFloorRgvList = SystemInit.getCurrentFloorZoneRgvList(rgv.getCurLocation().getZ(), nodeDB.getZoneId());
                if (CollectionUtils.isNotEmpty(currentFloorRgvList)) {
                    for (Rgv currentFloorRgv : currentFloorRgvList) {
                        if (!canAssign(currentFloorRgv) && currentFloorRgv.getCurTask() == null
                                && ((currentFloorRgv.getRgvStatus() == RgvStatus.CHARGING && currentFloorRgv.getBattery() >= currentFloorRgv.getRgvDB().getAssignBatterySize()) || currentFloorRgv.getRgvStatus() == RgvStatus.READY)
                                && !taskDBService.existUnFinishTask(currentFloorRgv)) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * 该车有充电任务的时候
     */
    private boolean existUnFinishChargingTask(Rgv rgv) {
        List<TaskDB> taskDBS = taskDBService.findUnFinishTaskByDistrictAndRgvNOAndTaskType(
                rgv.getRgvDB().getRgvNo().intValue(), TaskType.CHARGE);
        if (CollectionUtils.isNotEmpty(taskDBS)) {
            return true;
        }
        return false;
    }

    /**
     * 检验当前车辆是否满足重新配任务条件
     *
     * @param rgv
     * @return
     */
    private boolean canReassign(Rgv rgv) {
        if (rgv.getElectricStatus() == ElectricStatus.LOW_BATTERY
                || !rgv.getRgvDB().getOnline() || timeOutCount >= SysConfigUtil.NO_ASSIGN_TASK_TIME_OUT
                || (rgv.getRgvStatus() == RgvStatus.CHARGING && rgv.getBattery() < rgv.getRgvDB().getAssignBatterySize())
                || (rgv.getRgvStatus() == RgvStatus.CHARGING && rgv.getBattery() >= rgv.getRgvDB().getAssignBatterySize()
                && rgv.getBattery() < rgv.getRgvDB().getMaxBatterySize() && SystemInit.isTimeOut(rgv))) {
            return true;
        }
        return false;
    }


    /**
     * 检查当前车辆是否可以分配任务
     *
     * @param rgv
     * @return true 不可分配 false 可分配
     */
    private boolean canAssign(Rgv rgv) {
        if (rgv.getRgvStatus() == null || !rgv.getRgvDB().getOnline()
                || rgv.getRgvStatus() == RgvStatus.ERROR || rgv.getElectricStatus() == ElectricStatus.LOW_BATTERY
                || (rgv.getRgvStatus() == RgvStatus.CHARGING && rgv.getBattery() < rgv.getRgvDB().getAssignBatterySize())
                || (rgv.getRgvStatus() == RgvStatus.CHARGING && rgv.getBattery() >= rgv.getRgvDB().getAssignBatterySize()
                && rgv.getBattery() < rgv.getRgvDB().getMaxBatterySize() && SystemInit.isTimeOut(rgv))) {
            return true;
        }
        return false;
    }

    /**
     * 是否有空闲的车，如果有，则重新预分配（适用于同层不可多车，
     * 层多车少，一个车分配了多个层的任务时，需要重新调整任务分车）
     * 1.有其他层的任务，2.有空闲的小车
     */
    private boolean existNoCurrentFloorTask(Rgv rgv, List<TaskDB> preTaskList) {
        if (rgv.getCurLocation() != null) {
            List<TaskDB> taskDBList = taskDBService.findCurrentFloorPreTaskList(rgv.getRgvDB().getRgvNo(),
                    rgv.getCurLocation().getZ());
            preTaskList.removeAll(taskDBList);
            // 非当前层的任务
            if (CollectionUtils.isNotEmpty(preTaskList)) {
                NodeDB nodeDB = nodeDBService.getNodeDB(rgv.getCurLocation());
                List<Rgv> noCurrentFloorRgvList = SystemInit.getNoCurrentFloorZoneRgvList(rgv.getCurLocation().getZ(), nodeDB.getZoneId());
                if (CollectionUtils.isNotEmpty(noCurrentFloorRgvList)) {
                    for (Rgv noCurrentFloorRgv : noCurrentFloorRgvList) {
                        if (!canAssign(noCurrentFloorRgv) && noCurrentFloorRgv.getCurTask() == null
                                && ((noCurrentFloorRgv.getRgvStatus() == RgvStatus.CHARGING && noCurrentFloorRgv.getBattery() >= noCurrentFloorRgv.getRgvDB().getAssignBatterySize()) || noCurrentFloorRgv.getRgvStatus() == RgvStatus.READY)
                                && !taskDBService.existUnFinishTask(noCurrentFloorRgv)) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

}
